#include "ModelAnimation.h"

void AnimationAsset::OrderAnimation(std::shared_ptr<SkeletonAsset> skeletonAsset)
{
    std::vector<std::shared_ptr<std::vector<SRT>>> frames;

    frames.resize(cache.size());
    std::unordered_map<int, std::string> idtoNames; // anim id to name
    for (auto &kv : boneIdtoNames){
        if (skeletonAsset->animBoneNameIndex.find(kv.second) != skeletonAsset->animBoneNameIndex.end())
        {
            idtoNames[skeletonAsset->animBoneNameIndex[kv.second]] = kv.second;
        }
    }


    for (int frameCounter = 0; frameCounter < cache.size(); frameCounter++)
    {
        // 对原本的帧的骨骼变换进行重排序
        // 因为骨骼id和读取动画时不一样了，而帧的vector的index代表的是骨骼id
        // 所以需要重新排序
        // 这里只取anim骨骼
        std::shared_ptr<std::vector<SRT>> frame = std::make_shared<std::vector<SRT>>();
        frame->resize(skeletonAsset->animBoneNameIndex.size());
        for (int i = 0; i < boneIdtoNames.size(); i++) // 确保遍历所有骨骼动画，才能取到所有该保留的动画
        {
            // 这里不对劲！！！！
            if (skeletonAsset->animBoneNameIndex.find(boneIdtoNames[i]) != skeletonAsset->animBoneNameIndex.end())
            {
                (*frame)[skeletonAsset->animBoneNameIndex[boneIdtoNames[i]]] = (*cache[frameCounter])[i];
            }
        }
        frames[frameCounter] = frame;
    }

    std::shared_ptr<OrderedAnimation> anim = std::make_shared<OrderedAnimation>(frames, idtoNames);
    // std::cout<<name<<std::endl;

    anim->name = this->name.c_str();

    // 给skeletonAsset添加动画
    skeletonAsset->orderedAnimations.insert(std::make_pair(this->name, anim));
}

void OrderedAnimation::Export(std::string filename){
    FileWriter writer(filename);
    writer.Write("ORA_ANIM");
    writer.Write(name + '?');
    std::cout << "Export ANim: "<<name<<std::endl;

    uint32_t dictSize = boneIdtoNames.size();
    writer.WriteUInt32(dictSize);
    for (auto &kv : boneIdtoNames){
        writer.WriteInt32(kv.first);
        writer.Write(kv.second + '?');
    }

    uint32_t length = cache.size();
    writer.WriteUInt32(length);

    for(int i = 0; i < length; i++){
        uint32_t bones = cache[i]->size();
        writer.WriteUInt32(bones);
        for(int j = 0; j < bones; j++){
            writer.WriteVec3((*cache[i])[j].scale);
            writer.WriteQuat((*cache[i])[j].rotation);
            writer.WriteVec3((*cache[i])[j].translation);
        }
    }

    writer.Close();
}

OrderedAnimation::OrderedAnimation(std::string filename, std::shared_ptr<SkeletonAsset> skeleton)
{
    if (!FileReader::exists(filename))
        throw std::runtime_error("file not exists");

    FileReader reader(filename);
    std::string header = reader.ReadString(8);
    if (header != "ORA_ANIM")
        throw std::runtime_error("OrderedAnimation: read file which has error header");

    this->name = reader.ReadUntil();
    std::cout << "Import ANim: " << name << std::endl;

    uint32_t dictSize = reader.ReadUInt32();
    for (int i = 0; i < dictSize; i++)
    {
        int32_t id = reader.ReadInt32();
        std::string name = reader.ReadUntil();
        boneIdtoNames.insert(std::make_pair(id, name));
    }

    uint32_t length = reader.ReadUInt32();
    cache.resize(length);
    for(int i = 0; i < length; i++){
        uint32_t bones = reader.ReadUInt32();
        cache[i] = std::make_shared<std::vector<SRT>>();
        cache[i]->resize(bones);
        for(int j = 0; j < bones; j++){

            if (skeleton != nullptr && skeleton->animBoneNameIndex.find(boneIdtoNames[j]) != skeleton->animBoneNameIndex.end())
            {
                (*cache[i])[skeleton->animBoneNameIndex[boneIdtoNames[j]]].scale = reader.ReadVec3();
                (*cache[i])[skeleton->animBoneNameIndex[boneIdtoNames[j]]].rotation = reader.ReadQuat();
                (*cache[i])[skeleton->animBoneNameIndex[boneIdtoNames[j]]].translation = reader.ReadVec3();
            }
            else{
                (*cache[i])[j].scale = reader.ReadVec3();
                (*cache[i])[j].rotation = reader.ReadQuat();
                (*cache[i])[j].translation = reader.ReadVec3();
            }
        }
    }
    reader.Close();
}